/**
 * @author nttdocomo
 */
define(function(require) {
	require("./keyMap");
	aries.klass("aries.util.KeyNav", aries.Class.extend({
		initialize : function(config) {
			var me = this;
			if (arguments.length === 2) {
				me.legacyConstructor.apply(me, arguments);
				return;
			}
			me.setConfig(config);
		},

		/**
		 * Disables this KeyNav.
		 */
		disable : function() {
			this.map.disable();
			this.disabled = true;
		},

		/**
		 * Enables this KeyNav.
		 */
		enable : function() {
			this.map.enable();
			this.disabled = false;
		},

		/**
		 * @private
		 * Determines the event to bind to listen for keys. Defaults to the {@link #eventName} value, but
		 * may be overridden the {@link #forceKeyDown} setting.
		 *
		 * The useKeyDown option on the EventManager modifies the default {@link #eventName} to be `keydown`,
		 * but a configured {@link #eventName} takes priority over this.
		 *
		 * @return {String} The type of event to listen for.
		 */
		getKeyEvent : function(forceKeyDown, configuredEventName) {
			if (forceKeyDown || !configuredEventName) {
				return 'keydown';
			} else {
				return configuredEventName || this.eventName;
			}
		},

		/**
		 * @private
		 * Old constructor signature.
		 * @param {String/HTMLElement/Ext.Element} el The element or its ID to bind to
		 * @param {Object} config The config
		 */
		legacyConstructor : function(el, config) {
			this.setConfig($.extend({
				target : el
			}, config));
		},

		/**
		 * Sets up a configuration for the KeyNav.
		 * @private
		 * @param {String/HTMLElement/Ext.Element} el The element or its ID to bind to
		 * @param {Object} config A configuration object as specified in the constructor.
		 */
		setConfig : function(config) {
			var me = this, keymapCfg = {
				target : config.target,
				eventName : me.getKeyEvent('forceKeyDown' in config ? config.forceKeyDown : me.forceKeyDown, config.eventName)
			}, map, keyCodes, defaultScope, keyName, binding;

			if (me.map) {
				me.map.destroy();
			}

			if (config.processEvent) {
				keymapCfg.processEvent = config.processEvent;
				keymapCfg.processEventScope = config.processEventScope || me;
			}
			map = me.map = /*keymapCfg*/new aries.util.KeyMap(keymapCfg);
			keyCodes = me.constructor.keyOptions;
			defaultScope = config.scope || me;

			for (keyName in keyCodes) {
				if (keyCodes.hasOwnProperty(keyName)) {

					// There is a property named after a key name.
					// It may be a function or an binding spec containing handler, scope and defaultAction configs
					if ( binding = config[keyName]) {
						if ( typeof binding === 'function') {
							binding = {
								handler : binding,
								defaultAction : (config.defaultEventAction !== undefined) ? config.defaultEventAction : me.defaultEventAction
							};
						}
						map.addBinding({
							key : keyCodes[keyName],
							handler : _.bind(binding.handler || binding.fn, this), //Ext.Function.bind(me.handleEvent, binding.scope || defaultScope, binding.handler || binding.fn, true),
							defaultEventAction : (binding.defaultEventAction !== undefined) ? binding.defaultAction : me.defaultEventAction
						});
					}
				}
			}

			map.disable();
			if (!config.disabled) {
				map.enable();
			}
		}
	}, {
		keyOptions : {
			left : 37,
			right : 39,
			up : 38,
			down : 40,
			space : 32,
			pageUp : 33,
			pageDown : 34,
			del : 46,
			backspace : 8,
			home : 36,
			end : 35,
			enter : 13,
			esc : 27,
			tab : 9
		}
	}))
})
